﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Model.DocumentDB
{
    public class AccountViewModelCollection : LoadableCollection<AccountViewModel>
    {
        private const string NS = "uri://studio.documentDB/studio/1.0";
        private const string FILE_PATH = "Studio.xml";

        private object _selectedValue;

        /// <summary>See <see cref="INotifyPropertyChanged.PropertyChanged"/>.</summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>Constructor.</summary>
        public AccountViewModelCollection()
            : base(FileLoader)
        {
        }

        /// <summary>Add an account.</summary>
        /// <param name="accountViewModel">Model to add.</param>
        public void AddAccount(AccountViewModel accountViewModel)
        {
            if (accountViewModel == null)
            {
                throw new ArgumentNullException("accountViewModel");
            }
            if (HasError)
            {
                ClearError();
            }
            else if (!IsLoaded)
            {
                throw new InvalidOperationException("Accounts aren't loaded");
            }
            Add(accountViewModel);
        }

        /// <summary>Value selected.</summary>
        /// <remarks>Exists to propagate the information about selection.</remarks>
        public object SelectedValue
        {
            get { return _selectedValue; }
            set
            {
                _selectedValue = value;
                OnPropertyChanged(new PropertyChangedEventArgs("SelectedValue"));
                OnPropertyChanged(new PropertyChangedEventArgs("IsRefreshableSelected"));
                OnPropertyChanged(new PropertyChangedEventArgs("IsDatabaseFolderSelected"));
                OnPropertyChanged(new PropertyChangedEventArgs("IsDatabaseSelected"));
                OnPropertyChanged(new PropertyChangedEventArgs("IsCollectionFolderSelected"));
                OnPropertyChanged(new PropertyChangedEventArgs("IsCollectionSelected"));
            }
        }

        /// <summary><c>true</c> iif a refreshable collection is selected.</summary>
        /// <remarks>Exists for binding convenience.</remarks>
        public bool IsRefreshableSelected
        {
            get
            {
                var refreshable = SelectedValue as IRefreshable;

                return refreshable != null;
            }
        }

        /// <summary><c>true</c> iif a database folder is selected.</summary>
        /// <remarks>Exists for binding convenience.</remarks>
        public bool IsDatabaseFolderSelected
        {
            get { return SelectedValue != null && SelectedValue.GetType() == typeof(FolderViewModel<DatabaseViewModel>); }
        }

        /// <summary><c>true</c> iif a database root is selected.</summary>
        /// <remarks>Exists for binding convenience.</remarks>
        public bool IsDatabaseSelected
        {
            get { return SelectedValue != null && SelectedValue.GetType() == typeof(DatabaseViewModel); }
        }

        /// <summary><c>true</c> iif a collection folder is selected.</summary>
        /// <remarks>Exists for binding convenience.</remarks>
        public bool IsCollectionFolderSelected
        {
            get { return SelectedValue != null && SelectedValue.GetType() == typeof(FolderViewModel<CollectionViewModel>); }
        }

        /// <summary><c>true</c> iif a collection root is selected.</summary>
        /// <remarks>Exists for binding convenience.</remarks>
        public bool IsCollectionSelected
        {
            get { return SelectedValue != null && SelectedValue.GetType() == typeof(CollectionViewModel); }
        }

        /// <summary>Saves the model to file.</summary>
        /// <returns>Asynchronous completion.</returns>
        public async Task SaveAsync()
        {
            if (IsLoaded)
            {
                var ns = XNamespace.Get(NS);
                var accountElements = from a in this
                                      let id = new XAttribute("id", a.Id)
                                      let authKey = new XAttribute("authKey", a.AuthKey)
                                      select new XElement(ns + "account", id, authKey);
                var doc = new XDocument(new XElement(ns + "studio", new XElement(ns + "accounts", accountElements)));
                var content = doc.ToString();

                using (var writer = new StreamWriter(FILE_PATH))
                {
                    await writer.WriteAsync(content);
                }
            }
        }

        private async static Task<IEnumerable<AccountViewModel>> FileLoader()
        {
            if (File.Exists(FILE_PATH))
            {
                using (var reader = new StreamReader(FILE_PATH))
                {
                    var content = await reader.ReadToEndAsync();
                    var document = XDocument.Parse(content);
                    var ns = XNamespace.Get(NS);
                    var accountElements =
                        document.Element(ns + "studio").Element(ns + "accounts").Elements(ns + "account");
                    var accounts = from e in accountElements
                                   let id = e.Attribute("id").Value
                                   let authKey = e.Attribute("authKey").Value
                                   let model = new AccountViewModel(id, authKey)
                                   orderby model.Id
                                   select model;

                    return accounts.ToArray();
                }
            }

            return new AccountViewModel[0];
        }
    }
}